package mdt.figure;

import mdt.action.SetEdgeArrowAttrAction;
import mdt.action.SetFigShapeAttrAction;
import mdt.model.ConnectorAnchor;
import mdt.model.INodeModel;
import mdt.model.MDTMessage;
import org.tigris.gef.base.Layer;
import org.tigris.gef.base.Selection;
import org.tigris.gef.persistence.pgml.PgmlUtility;
import org.tigris.gef.presentation.*;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Iterator;
import java.util.Vector;

/**
 * Created by xiaobyu on 6/17/2016.
 */
public class FigMessage extends FigEdgePolyEditable{
    private static final long serialVersionUID = 1L;
    private PathItemPlacement itemPlace;

    public FigMessage(MDTMessage edge, Layer lay) {
        super(FigNodeEditable.TextType.MULTI_LINE);
        setDestArrowHead(createArrowHead(ARROW_TYPE.TRIANGLE));
        setFillColor(Color.black);
        initFigs();
        setOwner(edge);
    }

    public static enum ARROW_TYPE{
        NONE,
        HALF_TRIANGLE,
        TRIANGLE,
        GREATER,
        QUALIFIER,
        DIAMOND
    }

    public static ArrowHead createArrowHead(ARROW_TYPE type) {
        ArrowHead arrowHead;
        switch (type) {
            case NONE:
                return ArrowHeadNone.TheInstance;
            case HALF_TRIANGLE:
                arrowHead = new ArrowHeadHalfTriangle();
                arrowHead.setWidth(4);
                break;
            case TRIANGLE:
                arrowHead = new ArrowHeadTriangle();
                arrowHead.setWidth(4);
                break;
            case GREATER:
                arrowHead = new ArrowHeadGreater();
                arrowHead.setWidth(4);
                break;
            case QUALIFIER:
                arrowHead = new ArrowHeadQualifier();
                arrowHead.setWidth(4);
                break;
            case DIAMOND:
                arrowHead = new ArrowHeadDiamond();
                arrowHead.setWidth(4);
                break;
            default:
                arrowHead = ArrowHeadNone.TheInstance;
        }

        return arrowHead;
    }

    public void setSourceArrowHead(ArrowHead newArrow) {
        super.setSourceArrowHead(newArrow);
        newArrow.setFillColor(getFillColor());
        newArrow.setLineColor(getLineColor());
    }

    public void setDestArrowHead(ArrowHead newArrow) {
        super.setDestArrowHead(newArrow);
        newArrow.setFillColor(getFillColor());
        newArrow.setLineColor(getLineColor());
    }

    public void setFillColor(Color newColor) {
        super.setFillColor(newColor);
        getSourceArrowHead().setFillColor(newColor);
        getDestArrowHead().setFillColor(newColor);
    }

    int getFinalY() {
        int finalY = 0;
        Point[] points = getFig().getPoints();
        if (points.length > 0) {
            finalY = points[points.length - 1].y;
        }
        return finalY;
    }

    int getStartY() {
        int finalY = 0;
        Point[] points = getFig().getPoints();
        if (points.length > 0) {
            finalY = points[0].y;
        }
        return finalY;
    }

    public boolean hit(Rectangle r) {
        // Check if labels etc have been hit
        // Apparently GEF does require PathItems to be "annotations"
        // which ours aren't, so until that is resolved...
        Iterator it = getPathItemFigs().iterator();
        while (it.hasNext()) {
            Fig f = (Fig) it.next();
            if (f.hit(r)) {
                return true;
            }
        }
        return super.hit(r);
    }

    @Override
    public Selection makeSelection() {
        return new SelectionMessage(this);
    }

    private void initFigs() {
        setBetweenNearestPoints(true);

        initTextFig();
        FigTextMDT figText = getFigText();
        //figText.setTextFilled(false);
        figText.setLineWidth(0);
        figText.setEditable(true);
        figText.setFilled(false);
        figText.setBounds(new Rectangle(X0, Y0, 70, 20));
        itemPlace = new PathItemPlacement(this, figText, 50, 15);
        addPathItem(figText, itemPlace);
    }

    public Vector getPopUpActions(MouseEvent me) {
        Vector popUpActions = super.getPopUpActions(me);
        popUpActions.add(new JSeparator());
        popUpActions.add(new JMenuItem(new SetFigShapeAttrAction()));
        popUpActions.add(new JMenuItem(new SetEdgeArrowAttrAction()));
        return popUpActions;
    }

    public FigMessage cloneFig() {
        FigMessage fig = (FigMessage) super.cloneFig();
        fig.itemPlace = (PathItemPlacement) itemPlace.clone();
        fig.itemPlace.setPathFig(fig);
        fig.itemPlace.setItemFig(fig.getFigText());
        fig.addPathItem(fig.getFigText(), fig.itemPlace);
        return fig;
    }

    @Override
    public void mouseClicked(MouseEvent me) {
        if (!me.isConsumed() && me.getClickCount() >= 2) {
            Fig f = hitFig(new Rectangle(me.getX() - 2, me.getY() - 2, 4, 4));
            if (f instanceof MouseListener) {
                ((MouseListener) f).mouseClicked(me);
            }
        }
        me.consume();
    }

    protected boolean determineFigNodes() {
        Object owner = getOwner();
        if (owner == null) {
            return false;
        }
        if (getLayer() == null) {
            return false;
        }

        MDTMessage sm = (MDTMessage) owner;

        INodeModel newSource = sm.getSrcConnector().getConnectorOwner();
        INodeModel newDest = sm.getDstConnector().getConnectorOwner();

        FigNode newSourceFig = (FigNode) getNoEdgePresentationFor(newSource);
        FigNode newDestFig = (FigNode) getNoEdgePresentationFor(newDest);
        setSourcePortFig(newSourceFig.getPortFig(sm.getSrcConnector()));
        setDestPortFig(newDestFig.getPortFig(sm.getDstConnector()));
        if (newSourceFig != getSourceFigNode()) {
            setSourceFigNode(newSourceFig);
            newSourceFig.updateEdges();
        }
        if (newDestFig != getDestFigNode()) {
            setDestFigNode(newDestFig);
            newDestFig.updateEdges();
        }

        calcBounds();

        return true;
    }

    protected Object createEdgeConnectorModel() {
        return new ConnectorAnchor();
    }

    /**
     * A version of GEF's presentationFor() method which
     *
     * @param element ModelElement to return presentation for
     * @return the Fig representing the presentation
     */
    private Fig getNoEdgePresentationFor(Object element) {
        if (element == null) {
            throw new IllegalArgumentException("Can't search for a null owner");
        }

        java.util.List contents = PgmlUtility.getContentsNoEdges(getLayer());
        int figCount = contents.size();
        for (int figIndex = 0; figIndex < figCount; ++figIndex) {
            Fig fig = (Fig) contents.get(figIndex);
            if (fig.getOwner() == element) {
                return fig;
            }
        }
        throw new IllegalStateException("Can't find a FigNode representing " + element.getClass().getCanonicalName());
    }

    @Override
    public void renderingChanged() {
        damage();
    }
}
